﻿using Microsoft.Extensions.Caching.Memory;
using RestSharp;
using XYS.Core.Models;
using XYS.Core.Util;
using XYS.Service.Core.Util.Helper;

namespace XYS.Service.Core.Util.HttpInterceptors;

/// <summary>
/// http 请求日志 拦截器
/// </summary>
public class LogInterceptors : RestSharp.Interceptors.Interceptor
{
    private static IMemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions());


    private HttpLoggerInfo GetOrCreateHttpLoggerInfo(string code)
    {
        var httpLoggerInfo = memoryCache.Get<HttpLoggerInfo>(code);
        if (httpLoggerInfo == null)
        {
            httpLoggerInfo = new HttpLoggerInfo
            {
                Id = Guid.NewGuid(),
                BeginTime = DateTime.Now,
            };
            memoryCache.Set(code, httpLoggerInfo, TimeSpan.FromMinutes(30));
        }
        return httpLoggerInfo;
    }

    private HttpLoggerInfo GetHttpLoggerInfo(string code) => memoryCache.Get<HttpLoggerInfo>(code);


    /// <summary>
    /// 在编写请求消息之前拦截请求
    /// </summary>
    /// <param name="request"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public override ValueTask BeforeRequest(RestRequest request, CancellationToken cancellationToken)
    {
        if (!EnableLog) return base.BeforeRequest(request, cancellationToken);

        string requestCode = request.GetHashCode().ToString();
        var httpLoggerInfo = GetOrCreateHttpLoggerInfo(requestCode);
        httpLoggerInfo.Method = request.Method.ToString().ToUpper();

        var bodyParameter = request.Parameters.GetParameters(ParameterType.RequestBody).FirstOrDefault();
        if (bodyParameter != null) httpLoggerInfo.RequestBody = bodyParameter.Value.ToJson();

        request.AddHeader("_logger", requestCode);
        return base.BeforeRequest(request, cancellationToken);
    }

    /// <summary>
    /// 在发送之前拦截请求
    /// </summary>
    /// <param name="requestMessage"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public override ValueTask BeforeHttpRequest(HttpRequestMessage requestMessage, CancellationToken cancellationToken)
    {
        if (!EnableLog || requestMessage.RequestUri == null) return base.BeforeHttpRequest(requestMessage, cancellationToken);

        if (requestMessage.Headers.TryGetValues("_logger", out var loggerCodes) && !loggerCodes.IsNullOrEmpty())
        {
            var httpLoggerInfo = GetHttpLoggerInfo(loggerCodes.First());
            if (httpLoggerInfo == null) return base.BeforeHttpRequest(requestMessage, cancellationToken);

            httpLoggerInfo.ApiHost = requestMessage.RequestUri.Host;
            httpLoggerInfo.ApiPort = requestMessage.RequestUri.Port;
            httpLoggerInfo.ApiPath = requestMessage.RequestUri.AbsolutePath;
            httpLoggerInfo.QueryString = requestMessage.RequestUri.PathAndQuery;
            httpLoggerInfo.APIUrl = requestMessage.RequestUri.AbsoluteUri;

            requestMessage.Headers.Remove("_logger");
        }

        return base.BeforeHttpRequest(requestMessage, cancellationToken);
    }


    /// <summary>
    /// 从HttpResponseMessage创建请求后拦截请求
    /// </summary>
    /// <param name="response"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public override ValueTask AfterRequest(RestResponse response, CancellationToken cancellationToken)
    {
        if (!EnableLog) return base.AfterRequest(response, cancellationToken);

        string requestCode = response.Request.GetHashCode().ToString();
        var httpLoggerInfo = GetHttpLoggerInfo(requestCode);
        if (httpLoggerInfo == null) return base.AfterRequest(response, cancellationToken);


        httpLoggerInfo.ResponseBody = response.Content;
        httpLoggerInfo.StatusCode = (EnumStatusCode)response.StatusCode;
        httpLoggerInfo.StatusMessage = httpLoggerInfo.StatusCode.GetDescription();
        if (response.Headers != null)
        {
            foreach (var item in response.Headers)
            {
                var val = httpLoggerInfo.ResposeHeaders.FirstOrDefault(x => x.Key == item.Name);
                if (val != null) val.Value += "," + item.Value;
                else
                {
                    val = new KeyValueDTO<string, string>
                    {
                        Key = item.Name,
                        Value = item.Value
                    };
                    httpLoggerInfo.ResposeHeaders.Add(val);
                }
            }
        }
        httpLoggerInfo.EndTime = DateTime.Now;

        LogHelper.AddLog2Channel(httpLoggerInfo.Clone());
        return base.AfterRequest(response, cancellationToken);
    }

    private bool EnableLog => GlobalCoreSetting.HttpLoggerSetting != null && GlobalCoreSetting.HttpLoggerSetting.ChannelType != EnumAPILoggerChannelType.Unknown;

}
